package com.ems.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ems.dao.*;
import com.ems.dto.*;
import com.ems.entity.*;
import com.ems.entity.Score;
import com.ems.service.TeacherService;
import com.ems.utils.MDate;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

// 1/20宋
@Service
public class TeacherServiceImpl implements TeacherService {
    String[] abc = {"A","B","C","D","E","F","G","H","I","J","K"};

    @Autowired
    private ExamQuAnswerDao examQuAnswerDao;

    @Autowired
    private ExamPaperQuDao examPaperQuDao;

    @Autowired
    private ExamPaperQuAnswerDao examPaperQuAnswerDao;

    @Autowired
    private ExamPaperDao examPaperDao;

    @Autowired
    private SubjectDao subjectDao;

    @Autowired
    private QuestionDao questionDao;

    @Autowired
    private TeacherDao teacherDao;

    @Autowired
    private TeaExamDao teaExamDao;

    @Autowired
    private MyDtoMapper myDtoMapper;

    @Autowired
    private ExamDao examDao;

    @Autowired
    private StudentDao studentDao;

    @Autowired
    private StuExamDao stuExamDao;

    @Autowired
    private ExamPaperTempDao examPaperTempDao;

    @Autowired
    private ExamStuTempDao examStuTempDao;

    @Autowired
    private ScoreDao scoreDao;

    @Autowired
    private ExamCheckDao examCheckDao;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class IDS{
        private Integer qid;
        private Integer score;
        private String type;
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class RES{
        boolean isnull;
        boolean isException;
        Object data;
    }
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    public static class SSP{
        private Integer pqid;
        private Integer score;
    }
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    public static class QABE{
        private Integer uid;
        private Integer epid;
    }
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    public static class TQSS{
        private Integer score;
        private Integer uid;
        private Integer objScore;
        private Integer subjScore;
    }

    @Override
    public List<ExamInfo> inviTeacherId(String username) {
        Integer teaid = teacherDao.queryIDbyUsername(username);
        List<Integer> idList = teaExamDao.getIdByTid(teaid,1);
        System.out.println(idList);
        return myDtoMapper.inviExamInfo(idList);
    }

    @Override
    public List<ExamInfo> getExamInfo(String username){
        Integer teaid = teacherDao.queryIDbyUsername(username);
        List<Integer> idList = teaExamDao.getIdByTid(teaid, 0);
        System.out.println(idList);
        return myDtoMapper.inviExamInfo(idList);
    }

    @Override
    /*
    * 考试发布，在这里分配试卷
    * 在这里进行所有学生id的查询，并且存入临时表，方便阅卷

    * //TODO exam_paper title为空
    * */
    public boolean putExam(JSONObject jsonObject){
        Exam exam = new Exam();
        //先获取json里的data对象
        JSONObject json  = jsonObject.getJSONObject("data");
        //下面是data对象里的属性
        String title = json.getString("title");
        Integer totalTime = json.getInteger("totalTime");
        Integer totalScore = json.getInteger("totalScore");
        exam.setTotalScore(totalScore);
        exam.setEpid(json.getInteger("epid"));
        exam.setTitle(title);
        exam.setTotalTime(totalTime);
        exam.setInvigilatorA(json.getString("invigilatorA"));
        exam.setSubject(json.getString("subject"));
        exam.setPromulgator(teacherDao.getName(json.getString("username")));
        exam.setClassName(json.getString("class"));
        exam.setStartTime(json.getDate("start"));
        exam.setEndTime(json.getDate("end"));
        exam.setDescribes(json.getString("describes"));
        exam.setInvigilatorB(json.getString("invigilatorB"));
        exam.setIsbegin(0);
        exam.setCreatTime(new Date());
        //插入考试信息
        examDao.insert(exam);
        //获取考试id
        Integer eid = exam.getId();
        //System.out.println(eid);

        //查询出这个班级的所有学生
        List<Integer> allClassUserId = studentDao.queryIdByClassName(json.getString("class"));
        //System.out.println(allClassUserId);

        List<StuExam> stuExams = new ArrayList<>();
        Iterator<Integer> iterator = allClassUserId.iterator();
        //获取临时存储的试卷信息
        ExamPaperTemp examPaperTemp = examPaperTempDao.queryByEpid(json.getInteger("epid"));
        String examPaperJson = examPaperTemp.getExamPaperJson();
        JSONObject examPaperT= JSONObject.parseObject(examPaperJson);

        //循环构建实体类
        while (iterator.hasNext())
        {
            Integer uid = iterator.next();
            StuExam stuExam = new StuExam();
            stuExam.setIsjoin(0);
            stuExam.setEid(eid);
            stuExam.setStuid(uid);
            stuExam.setIsfinish(0);
            stuExams.add(stuExam);
            CEPaper(examPaperT,uid,false,false,eid,totalTime,title);
        }
        //考试关联学生
        stuExamDao.insertBatch(stuExams);
        //考试关联老师
        String invigilatorA = json.getString("invigilatorA");
        String invigilatorB = json.getString("invigilatorB");
        Integer Aid = teacherDao.queryIDbyName(invigilatorA);
        Integer Bid = teacherDao.queryIDbyName(invigilatorB);

        if(Aid != null)
        {
            TeaExam teaExam = new TeaExam();
            teaExam.setEid(eid);
            teaExam.setTeaid(Aid);
            teaExam.setSignals(1);
            teaExamDao.insert(teaExam);
        }
        if(Bid != null)
        {
            TeaExam teaExam = new TeaExam();
            teaExam.setEid(eid);
            teaExam.setTeaid(Bid);
            teaExam.setSignals(1);
            teaExamDao.insert(teaExam);
        }
        //给发布的老师绑定考试信息
        TeaExam teaExam = new TeaExam();
        teaExam.setSignals(0);
        teaExam.setEid(eid);
        teaExam.setTeaid(teacherDao.queryIDbyUsername(json.getString("username")));
        teaExamDao.insert(teaExam);

        //查询所有的学生id，放入exam_stu_temp表中
        List<Integer> allStuID = examPaperDao.queryAllUidByEid(eid);
        ExamStuTemp examStuTemp = new ExamStuTemp();
        examStuTemp.setStuId(JSON.toJSONString(allStuID));
        examStuTemp.setEid(eid);
        examStuTempDao.insert(examStuTemp);

        //回调更新exam_paper表的exam_id
        ExamPaper examPaper = new ExamPaper();
        examPaper.setExamId(eid);
        examPaper.setTitle(title);
        examPaper.setTotalTime(totalTime);
        examPaper.setId(json.getInteger("epid"));
        examPaperDao.update(examPaper);

        //标记没有进行计算分数
        ExamCheck examCheck = new ExamCheck();
        examCheck.setEid(eid);
        examCheck.setIscheck(0);
        examCheckDao.insert(examCheck);
        return true;

    }

    @Override
    public boolean register(JSONObject jsonObject) {
        Teacher teacher = new Teacher();
        JSONObject json = jsonObject.getJSONObject("data");

        teacher.setUsername(json.getString("username"));
        teacher.setPassword(json.getString("password"));
        teacher.setPhone(json.getString("phone"));
        teacher.setEmail(json.getString("email"));
        teacher.setPermission(json.getString("permission"));
        teacher.setAcademy(json.getString("academy"));
        teacher.setName(json.getString("name"));
        teacher.setSex(json.getInteger("sex"));
        teacher.setAge(json.getInteger("age"));
        teacher.setWechat(json.getString("wechat"));

        return teacherDao.insert(teacher) != 0;
    }

    @Override
    public boolean delExam(Integer eid, Integer tid) {
        //TODO 删除500错误 看看
        teaExamDao.deleteByEidAndTid(eid,tid);
        return true;
    }

    @Override
    public List<QsubjectiveQuestions> queryQuestion_subjectiveQuestions(String subject,Integer difficulty,String point) {
        //构建查询参数对象
        Question question = new Question();

        //去查询科目id，可优化
        Integer subid = subjectDao.queryIdByName(subject);

        //set参数值
        question.setSubid(subid);
        question.setDifficulty(difficulty);
        question.setPointA(point);
        question.setPointB(point);
        question.setQuestionType("主观题");

        return questionDao.queryQuestion_subjectiveQuestions(question);
    }

    @Override
    public List<Choice> queryQuestion_singleChoice(String subject,Integer difficulty,String point) {
        //构建查询参数对象
        Question question = new Question();

        //去查询科目id，可优化
        Integer subid = subjectDao.queryIdByName(subject);

        //set参数值
        question.setSubid(subid);
        question.setDifficulty(difficulty);
        question.setPointA(point);
        question.setPointB(point);
        question.setQuestionType("单选题");

        return myDtoMapper.queryQuestion_singleChoice(question);
    }

    @Override
    public List<Choice> queryQuestion_multipleChoice(String subject,Integer difficulty,String point) {
        //构建查询参数对象
        Question question = new Question();

        //去查询科目id，可优化
        Integer subid = subjectDao.queryIdByName(subject);

        //set参数值
        question.setSubid(subid);
        question.setDifficulty(difficulty);
        question.setPointA(point);
        question.setPointB(point);
        question.setQuestionType("多选题");

        return myDtoMapper.queryQuestion_multipleChoice(question);
    }

    @Override
    public StudentAnswer markPaper(Integer eid, Integer uid) {
        return myDtoMapper.markPaper(eid,uid);
    }

    @Override
    //默认在
    public Integer creatExamPaper(JSONObject jsonObject) {

        //创建母卷
        Integer epid = CEPaper(jsonObject, -1, true,true,-1,0,null);
        //这里应该处理异常
        return epid;
    }

    //创建试卷的函数，通过isMu来判断是不是母卷的创建
    public Integer CEPaper(JSONObject jsonObject ,Integer uid,Boolean isMu,Boolean isCreatTempPaper,Integer eid,Integer totalTime,String title){

        ExamPaper examPaper = new ExamPaper();
        ExamPaperQu examPaperQu = new ExamPaperQu();
        ExamPaperQuAnswer quAnswer = new ExamPaperQuAnswer();
        ExamPaperTemp examPaperTemp = new ExamPaperTemp();

        JSONObject json = jsonObject.getJSONObject("data");
        Integer totalQuestions = json.getInteger("totalQuestions"); 
        Integer examid = json.getInteger("examid");
        Integer totalScore = json.getInteger("totalScore");
        Integer SNumber = json.getInteger("SNumber");
        Integer MNumber = json.getInteger("MNumber");
        Integer subNumber = json.getInteger("subjNumber");
        Integer sScore = json.getInteger("SScore");
        Integer mScore = json.getInteger("MScore");
        Integer subScore = json.getInteger("SubScore");
        List<IDS> singleChoice = json.getObject("singleChoice", ArrayList.class);
        List<IDS> multipleChoice = json.getObject("multipleChoice",ArrayList.class);
        List<IDS> subjectiveQuestion = json.getObject("subjectiveQuestion",ArrayList.class);

        if(eid != -1) examPaper.setExamId(eid);
        //构建Exam Paper对象
        //TODO 这里考试标题是空，需要解决
        examPaper.setTitle(title);
        examPaper.setTotalScore(totalScore);
        examPaper.setQualifyScore((int) (totalScore*0.6));
        examPaper.setTotalTime(totalTime);
        //在这里获取当前时间，设置创建时间属性
        examPaper.setCreateTime(MDate.getCurrentTime());



        if(subNumber != 0) examPaper.setHasSaq(1);
        else examPaper.setHasSaq(0);
        //标记母卷
        if(isMu)
        {
            examPaper.setUserTime(-1);
        }
        else
        {
            examPaper.setUserTime(0);
            examPaper.setUserId(uid);
        }

        examPaperDao.insert(examPaper);
        Integer epid = examPaper.getId();

        //存储试卷的信息，方便分配试卷
        if(isCreatTempPaper){
            examPaperTemp.setExamPaperJson(jsonObject.toJSONString());
            examPaperTemp.setEpid(epid);
            examPaperTempDao.insert(examPaperTemp);
        }

        Iterator<IDS> Site = singleChoice.iterator();
        Iterator<IDS> Mite = multipleChoice.iterator();
        Iterator<IDS> SUBite = subjectiveQuestion.iterator();

        int sort = 0;
        while(Site.hasNext()){
            String jsonString = JSON.toJSONString(Site.next());
            IDS ids = JSONObject.parseObject(jsonString, IDS.class);
            examPaperQu.setPaperId(epid);
            examPaperQu.setQuId(ids.getQid());
            examPaperQu.setScore(ids.getScore());
            examPaperQu.setQuType(ids.getType());
            examPaperQu.setAnswered(0);
            examPaperQu.setSort(++sort);

            //对答案进行排序
            List<ExamQuAnswer> examQuAnswers = examQuAnswerDao.queryByQId(ids.getQid());
            int index = 0;
            for (ExamQuAnswer answer: examQuAnswers) {
                quAnswer.setPaperId(epid);
                quAnswer.setAnswerId(answer.getId());
                quAnswer.setQuId(ids.getQid());
                quAnswer.setIsRight(answer.getIsRight());
                quAnswer.setChecked(0);
                quAnswer.setSort(index+1);
                quAnswer.setAbc(abc[index++]);
                System.out.println(quAnswer);
                examPaperQuAnswerDao.insert(quAnswer);
            }
            examPaperQuDao.insert(examPaperQu);
        }
        sort = 0;
        while(Mite.hasNext()){
            String jsonString = JSON.toJSONString(Mite.next());
            IDS ids = JSONObject.parseObject(jsonString, IDS.class);
            examPaperQu.setPaperId(epid);
            examPaperQu.setQuId(ids.getQid());
            examPaperQu.setScore(ids.getScore());
            examPaperQu.setQuType(ids.getType());
            examPaperQu.setSort(sort++);

            //这里应该定义事务，如果出现错误不应该提交事务，以免污染数据，或者插入非法数据
            examPaperQuDao.insert(examPaperQu);

            //对答案进行排序
            List<ExamQuAnswer> examQuAnswers = examQuAnswerDao.queryByQId(ids.getQid());
            int index = 0;
            for (ExamQuAnswer answer: examQuAnswers) {
                quAnswer.setPaperId(epid);
                quAnswer.setAnswerId(answer.getId());
                quAnswer.setQuId(ids.getQid());
                quAnswer.setIsRight(answer.getIsRight());
                quAnswer.setChecked(0);
                quAnswer.setSort(index+1);
                quAnswer.setAbc(abc[index++]);
                System.out.println(quAnswer);
                examPaperQuAnswerDao.insert(quAnswer);
            }
        }

        sort = 0;
        while(SUBite.hasNext()){
            String jsonString = JSON.toJSONString(SUBite.next());
            IDS ids = JSONObject.parseObject(jsonString, IDS.class);
            examPaperQu.setPaperId(epid);
            examPaperQu.setQuId(ids.getQid());
            examPaperQu.setScore(ids.getScore());
            examPaperQu.setQuType(ids.getType());
            examPaperQu.setSort(sort++);
            examPaperQuDao.insert(examPaperQu);
        }

        //这里应该检查是否出现异常
        return epid;
    }


    @Override
    public TeacherExamPaper getExamPaper(Integer eid) {
        return myDtoMapper.teacherGetExamPaper(eid);
    }

    //自动校验客观题答案
    @Override
    public void checkAnswer(Integer eid) {
        /*
        * 这里只计算分数，检查是否正确在学生提交的时候就检查
        * 1.先查询出这场考试的所有考生试卷（user_time不是-1的）
        * 2.查询出第一个试卷id的客观题进行核对（多选题原则是选错一个就不得分）
        * 3.循环操作
        * 应该先确定，考试是否完结，不完结无法阅卷
        * */
        List<Integer> Epids = examDao.queryIdByEid(eid);

        Iterator<Integer> iterator = Epids.iterator();
        while(iterator.hasNext()){
            Integer pid = iterator.next();
            int sum = 0;
            List<Integer> scores = examPaperQuDao.calculateCheck(pid);
            for(Integer s : scores)
            {
                sum += s;
            }
            System.out.println(sum);
            //将客观题得分插入数据库
            examPaperDao.updateObjScore(pid,sum);
        }

    }

    @Override
    public ExamAnalyze examAnalyze(Integer eid) {

        //定义部分
        ExamAnalyze examAnalyze = new ExamAnalyze();
        ExamAnalyze.examinfo examinfo = new ExamAnalyze.examinfo();

        //TODO 还没看明白问题id与试卷id对应关系
        ExamAnalyze.question question = new ExamAnalyze.question();

        ExamAnalyze.studentScore studentScore = null;
        ArrayList<ExamAnalyze.studentScore> studentScores = new ArrayList<>();


        int stuNumber = 0;
        int aveTime = 0;
        int pass = 0;
        int nopass = 0;


        Exam exam = examDao.queryById(eid);
        List<ExamPaper> examPapers = examPaperDao.queryAllPaperSameExam(eid);
        //母卷
        ExamPaper mainPaper = new ExamPaper();


        for(ExamPaper e : examPapers) {
            if(e.getUserTime()==-1) {
                mainPaper = e;
            }else{
                aveTime += e.getUserTime();
                if (e.getUserScore() >= e.getQualifyScore()) {
                    pass++;
                } else {
                    nopass++;
                }
                studentScore = new ExamAnalyze.studentScore();
                studentScore.setName(studentDao.queryNameById(e.getUserId()));
                studentScore.setScore(e.getUserScore());

                studentScore.setStatus("正常");

                studentScores.add(studentScore);
                stuNumber++;
            }
        }

        //TODO null 空指针了
        //examinfo.setTitle(exam.getTitle());
//        System.out.println(examinfo.getTitle());
        examinfo.setBeginTime(exam.getStartTime());
//        System.out.println(exam.getStartTime());
        examinfo.setAveTime(aveTime/stuNumber);
//        System.out.println(examinfo.getAveTime());

        //TODO 完成度还没做，是整张试卷是否完成
        examinfo.setFinishProgressRate(new Double(0.99));

        examinfo.setPass(pass);
//        System.out.println(examinfo.getPass());
        examinfo.setNopass(nopass);
//        System.out.println(examinfo.getNopass());
        examinfo.setStuNumber(stuNumber);


        //TODO 不知为啥是Null
        List<ExamPaperQu> sorts = examPaperQuDao.querySortById(mainPaper.getId());
        ArrayList<ExamAnalyze.question.choice> singleQu = new ArrayList<ExamAnalyze.question.choice>();
        ArrayList<ExamAnalyze.question.choice> multiQu = new ArrayList<ExamAnalyze.question.choice>();

        //循环找
        for(ExamPaperQu epq:sorts){
            ExamAnalyze.question.choice temp = new ExamAnalyze.question.choice();
            temp.setSort(epq.getSort());
            temp.setRight(teaExamDao.queryRightNumber(epq.getQuId()));
    //TODO 还没分单选多选!
            if(epq.getQuType().equals("单选题")) {
                    singleQu.add(temp);
                }else if(epq.getQuType().equals("多选题")) {
                    multiQu.add(temp);
                }
        }
        question.setSingle(singleQu);
        question.setMultiple(multiQu);


        examAnalyze.setExaminfo(examinfo);
        examAnalyze.setQuestion(question);
        examAnalyze.setStudentScores(studentScores);

        return examAnalyze;
    }

    @Override
    public Teacher queryByUsername(String username) {
        return teacherDao.queryByUsername(username);
    }

    @Override
    public void putQuestion(Question question){
        questionDao.insert(question);
    }

    @Override
    public boolean studentScorePut(JSONObject jsonObject) {
        JSONObject data = jsonObject.getJSONObject("data");
        ArrayList<SSP> questions = data.getObject("questions", ArrayList.class);

        Iterator<SSP> iterator = questions.iterator();

        for (Object object: questions) {
            String s = JSON.toJSONString(object);
            SSP ssp = JSONObject.parseObject(s, SSP.class);
            try{
                examPaperQuDao.updateScoreByTeacher(ssp.getPqid(),ssp.getScore());
            }catch (Exception e){
                System.out.println(e.getLocalizedMessage());
                return false;
            }
        }
        return true;
    }

    @Override
    /*
    //TODO 晚上看看写的有没有问题，排名哪里
    * 老师获取学生答题卡
    * 利用在数据库储存，单张获取
    * */
    public Object getStudentPaper(Integer eid){

        StudentAnswer studentAnswer;
        String stuID = examStuTempDao.queryByEId(eid);
        List<Integer> id = JSON.parseArray(stuID, Integer.class);

        if (!allStudentPutAnswer(eid)) return new RES(false,true,null);

        //判断还有没有未批阅的学生
        if(id.isEmpty()) return new RES(true,false,null);


        int uid = id.get(0);
        try{
            studentAnswer = markPaper(eid, uid);
        }catch (Exception e){
            System.out.println(e);
            return new RES(false,true,null);
        }

        //remove已经批阅的
        id.remove(0);

        stuID = JSON.toJSONString(id);
        examStuTempDao.updateByEid(stuID,eid);

        return new RES(false,false,studentAnswer);
    }

    @Override
    //计算总分数+阅卷客观题
    public Object calculateScore(JSONObject jsonObject) {
        JSONObject data = jsonObject.getJSONObject("data");
        System.out.println(data);
        Integer eid = data.getInteger("eid");
        System.out.println("111:考试id："+ eid);

        //检查学生是否全部完成答题
        if (allStudentPutAnswer(eid));
        else return new RES(false,true,null);

        //检查是否已经计算过
        ExamCheck examCheck = examCheckDao.queryByEid(eid);
        if (examCheck == null) return new RES(true,true,null);
        if (examCheck.getIscheck() == 1) return new RES(false,true,null);

        System.out.println("开始计算客观题总分数");
        checkAnswer(eid);
        System.out.println("开始计算主观题总分数");
        //QABE包括学生id和试卷idqa
        List<QABE> qabeList = examPaperDao.queryExamAllStuID(eid);
        for(QABE qabe: qabeList){
            int score = 0;
            List<Integer> scores = examPaperQuDao.queryScoreByEpid(qabe.getEpid());
            for(Integer s:scores){
                score += s;
            }

            //查询出来客观题分数
            ExamPaper ep = examPaperDao.queryById(qabe.getEpid());
            ExamPaper examPaper = new ExamPaper();
            examPaper.setId(qabe.epid);
            examPaper.setSubjScore(score);
            examPaper.setUserScore(score + ep.getObjScore());
            examPaperDao.update(examPaper);

            //在score表中插入数据
            //TODO 500错误，疯狂插入
            Score stuScore = new Score();
            stuScore.setScore((double) (score + ep.getObjScore()));
            stuScore.setEid(eid);
            stuScore.setStuid(qabe.uid);
            scoreDao.insert(stuScore);
        }

        //查询出学生的总成绩，客观成绩，主观成绩，排名规则，总成绩优先其次客观成绩再主观成绩
        List<TQSS> tqssList = examPaperDao.queryStudentScore(eid);
        //重写排序规则
        Comparator<TQSS> comp= new Comparator<>(){

            @Override
            public int compare(TQSS o1, TQSS o2) {
                if(o1.score == o1.score)
                    return o1.objScore - o2.objScore;
                else
                    return o1.score - o1.score;
            }
        };

        tqssList.sort(comp);
        System.out.println(tqssList);

        //进行排名插入
        int ranking = 0;
        for(TQSS t: tqssList){
            Score score = new Score();
            score.setEid(eid);
            score.setStuid(t.getUid());
            score.setRangking(++ranking);
            scoreDao.updateByEidAndUid(score);
        }

        examCheck.setIscheck(1);
        examCheckDao.update(examCheck);
        return new RES(false,false,null);
    }

    public  boolean allStudentPutAnswer(Integer eid){

        List<Integer> finish = stuExamDao.queryIsFinishByEid(eid);
        if(finish.contains(0)) return false;

        return true;
    }
}
